﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
using FluentDml.Linq;
using NHibernate;

namespace FluentDml
{
    /// <summary>
    /// Apply a Update set based function
    /// </summary>
    /// <typeparam name="T">the type to apply set based operation against</typeparam>
    public class Update<T> : Command<T>
    {
        public Update(ISession session, Expression<Func<T, bool>> where) : base(session, where) { }
        readonly IList<PropertyMap> _propertyMaps = new List<PropertyMap>();

        /// <summary>
        /// Properties to set new values against
        /// </summary>
        /// <typeparam name="TProperty">the property type</typeparam>
        /// <param name="property">the property</param>
        /// <param name="value">the new value</param>
        public Update<T> Set<TProperty>(Expression<Func<T, TProperty>> property, TProperty value)
        {
            var member = FindMemberVisitor.GetMember(property);
            NamedParameter namedParameter = ParameterAggregator.AddParameter(value);

            PropertyMap propertyMap = new PropertyMap(member, namedParameter.Name);
            _propertyMaps.Add(propertyMap);

            return this;
        }

        private string GetSetParameters(string alias)
        {
            StringBuilder buffer = new StringBuilder();
            foreach (var propertyMap in _propertyMaps)
            {
                if (buffer.Length != 0)
                {
                    buffer.Append(", ");
                }
                buffer.AppendFormat("{0}.{1} = :{2} ", alias, propertyMap.PropertyName, propertyMap.Parameter);
            }
            return buffer.ToString();
        }

        protected override string CreateCommandString(string alias)
        {
            if (string.IsNullOrEmpty(alias)) throw new ArgumentNullException("alias");

            string fullName = typeof(T).FullName;
            return string.Format("update {0} as {1} set {2}", fullName, alias, GetSetParameters(alias));
        }
    }
}